package com.woniuxy.sales.controller;

import cn.hutool.core.util.RandomUtil;
import com.woniuxy.sales.common.RedisConst;
import com.woniuxy.sales.common.enumeration.BusinessCode;
import com.woniuxy.sales.model.dto.LoginRequest;
import com.woniuxy.sales.model.entity.Users;
import com.woniuxy.sales.model.vo.ChangePasswordRequest;
import com.woniuxy.sales.model.vo.RegisterRequest;
import com.woniuxy.sales.model.vo.UsersVo;
import com.woniuxy.sales.service.UsersService;
import com.woniuxy.sales.untils.Assert;
import com.woniuxy.sales.untils.JwtTemplate;
import com.woniuxy.sales.untils.QiNiuUploadUtils;
import com.woniuxy.sales.untils.SmsUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.Book;
import java.io.IOException;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/users")
@Slf4j
@Api(tags = "用户接口")
public class UsersController {
    @Autowired
    private UsersService usersService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private JwtTemplate jwtTemplate;
    @Autowired
    private JavaMailSender mailSender;
    @Value("${spring.mail.username}")
    private String from;

    // @RequestPart 接受 前端 传递过来的图片
    @PostMapping("/upload")
    @ApiOperation("文件上传")
    public ResponseEntity<?> upload(@RequestPart MultipartFile file) throws IOException {
        // 1. 获取文件名称
        String originalFilename = file.getOriginalFilename();
        // 2. 重新设置文件的名称
        String uuid = UUID.randomUUID().toString();
        // 文件的名称 = uuid + 源文件的后缀
        String substring = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileName = uuid + substring;
        //图片的- 替换
        fileName = fileName.replaceAll("-", "");
        // 3. 调用图片上传的工具类
        QiNiuUploadUtils.uploadFile(file.getBytes(), fileName);
        log.info("回调的数据：{}", fileName);
        // 4. 响应数据
        //imageUrl = 外连接 + fileName
        //http://smglht3z4.hn-bkt.clouddn.com/2bb647d6-4467-4e0b-893d-b2399d448161.jpg
        String imageUrl = "http://smglht3z4.hn-bkt.clouddn.com/" + fileName;
        return ResponseEntity.ok(imageUrl);
    }

    @ApiOperation("删除图片")
    @GetMapping("/delete")
    public ResponseEntity<?> delete(String fileName) {
        QiNiuUploadUtils.deleteFile(fileName);
        return ResponseEntity.ok("删除图片成功");
    }

    @PostMapping("/check-password")
    @ApiOperation("验证密码")
    public ResponseEntity<?> checkPassword(@RequestBody ChangePasswordRequest request,
                                           @RequestHeader("Authorization") String token) {
        usersService.checkPassword(token, request);
        return ResponseEntity.ok("密码验证成功");
    }

    /**
     * 修改密码
     */
    @PostMapping("/change-password")
    @ApiOperation("修改密码")
    public ResponseEntity<?> changePassword(@RequestBody ChangePasswordRequest request
            , @RequestHeader("Authorization") String token) {
        //删除redis中的token
        stringRedisTemplate.delete(RedisConst.USERS_TOKEN_PREFIX + ":" + request.getUserId());
        usersService.changePassword(request);
        stringRedisTemplate.opsForValue()
                .set(RedisConst.USERS_TOKEN_PREFIX + ":" + request.getUserId(), token, Duration.ofDays(1));
        return ResponseEntity.ok("修改密码成功");
    }

    /**
     * 退出
     */
    @DeleteMapping("/logout")
    @ApiOperation("退出")
    public ResponseEntity<String> logout(@RequestHeader("Authorization") String token, HttpServletResponse response) {
        //通过token得到用户id
        String userId = jwtTemplate.getValue(token, "userId");
        //删除redis中的token
        stringRedisTemplate.delete(RedisConst.USERS_TOKEN_PREFIX + ":" + userId);
        //清除缓存
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Expires", "0");
        return ResponseEntity.ok("退出成功");
    }

    /**
     * 显示个人信息
     */
    @GetMapping("/findById")
    @ApiOperation("通过ID显示用户信息")
    public ResponseEntity<Users> findById(@RequestHeader("Authorization") String token) {
        Users user = usersService.findById(token);
        return ResponseEntity.ok(user);
    }

    @GetMapping("/sendEmail/{email}")
    @ApiOperation("发送邮件")
    public ResponseEntity<String> sendEmail(@PathVariable String email) {
        //发送邮件
        SimpleMailMessage mail = new SimpleMailMessage();
        mail.setFrom(from);
        mail.setTo(email);
        mail.setSubject("汽车商城：验证码");
        String text = RandomUtil.randomNumbers(4);
        String context = "注册的验证码是：" + text + "，该验证码15分钟内有效！";
        mail.setText(context);
        //开启一个后台线程发送邮件
        new Thread(() -> {
            //发送成功后测试将该代码注释
            //模拟发送邮件
//            mailSender.send(mail);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("邮箱验证码：{}", text);
        }).start();
        //将数据储存在redis中
        stringRedisTemplate.opsForValue().set(RedisConst.EMAIL_ADDRESS_PREFIX + ":"
                + email, text, RedisConst.EMAIL_CODE_EXPIRE, TimeUnit.MINUTES);
        return ResponseEntity.ok("验证码已经发送到" + email + "邮箱，请查收！");
    }

    /**
     * 用户注册功能
     */
    @PostMapping("/register")
    @ApiOperation("用户注册")
    public ResponseEntity<?> register(@RequestBody RegisterRequest registerRequest, HttpServletRequest request) {
        //从Redis中获取验证码是否正确
        String redisCode = stringRedisTemplate.opsForValue().get(RedisConst.SHORT_MESSAGE_SERVICE +
                ":" + registerRequest.getPhone());
        //判断验证码是否过期
        Assert.error(Objects.isNull(redisCode), BusinessCode.INVALID_VERIFICATION);

        //判断验证码是否正确
        Assert.error(!redisCode.equals(registerRequest.getValidCode()), BusinessCode.VERIFICATION_ERROR);

        //判断用户名是否重复
        Assert.error(usersService.isUsernameExist(registerRequest.getUsername()), BusinessCode.USER_IS_EXIST);

        //判断手机号码是否重复
        Assert.error(usersService.isPhoneExist(registerRequest.getPhone()), BusinessCode.PHONE_IS_EXIST);

        //创建用户对象
        Users user = new Users();
        //将注册信息复制到user对象中
        BeanUtils.copyProperties(registerRequest, user);
        user.setRegistrationDate(new Date());

        //调用业务层注册
        Users newUser = usersService.register(user);

        //默认已经登录
        return createTokenAndUserVo(request, newUser);

    }

    /**
     * 用户名和密码，验证码登录
     */
    @PostMapping("/login")
    @ApiOperation("用户名登录")
    public ResponseEntity<?> login(@RequestBody LoginRequest param, HttpServletRequest request) {
        //1.调用业务层进行登录
        ResponseEntity<?> responseEntity = usersService.login(param);
        //2.如果登录成功则创建Token
        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            //得到用户对象
            Users users = (Users) responseEntity.getBody();
            //登录成功，创建Token
            ResponseEntity<?> entity = createTokenAndUserVo(request, users);
            return entity;
        } else {
            //登录失败，返回错误信息
            return responseEntity;
        }
    }


    /**
     * 生成Token，并且封装UserVo对象
     */
    private ResponseEntity<UsersVo> createTokenAndUserVo(HttpServletRequest request, Users users) {
        //1.生成Token
        HashMap<String, Object> data = new HashMap<>();
        data.put("userId", users.getUserId());
        data.put("userName", users.getUsername());
        //为了安全，判断IP地址是否相同
        data.put("ip", jwtTemplate.getRequestIP(request));
        //生成Token
        String token = jwtTemplate.createToken(data);
        log.info("用户ID：{} 登录成功，生成的Token为：{}", users.getUserId(), token);

        //2.存储到Redis中，保存1天
        String key = RedisConst.USERS_TOKEN_PREFIX + ":" + users.getUserId();
        stringRedisTemplate.opsForValue().set(key, token, Duration.ofDays(1));

        //3.封装UserVo对象
        UsersVo usersVo = new UsersVo();
        //复制属性：源对象，目标对象
        BeanUtils.copyProperties(users, usersVo);

        //4.以响应头的方式发送Token回去
        return ResponseEntity.ok()
                .header("Authorization", token)
                //告知浏览器可以访问 Authorization 响应头，否则访问不了
                .header("Access-Control-Expose-Headers", "Authorization")
                .body(usersVo);
    }


    /**
     * 图片验证码
     */
    @GetMapping("/code")
    @ApiOperation("生成图片验证码")
    public ResponseEntity generateCaptcha() throws IOException {
        //2) 创建缓存图片：指定宽
        int width = 110, height = 45;
        //参数3：图片的类型，使用RGB类型
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //3) 获取画笔对象
        Graphics graphics = image.getGraphics();
        //4) 设置画笔颜色，并且填充矩形区域
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, width, height);
        //创建一个StringBuider对象
        StringBuilder sb = new StringBuilder();
        //5) 从字符数组中随机得到字符
        String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        char[] arr = characters.toCharArray();

        Random random = new Random();

        for (int i = 0; i < 4; i++) {
            //随机从0到长度之间去取索引
            int index = random.nextInt(arr.length);
            //得到1个字符
            char c = arr[index];
            sb.append(c);
            //6) 设置字体，大小为22，设置字的颜色随机
            graphics.setFont(new Font(null, Font.BOLD + Font.ITALIC, 22));
            graphics.setColor(getColor());
            //7) 将每个字符画到图片，位置：5+(i*23), 25
            //将字符转成字符串
            graphics.drawString(String.valueOf(c), 5 + (i * 23), 25);
        }

        //8) 画干扰线8条线，线的位置是随机的，x范围在width之中，y的范围在height之中。
        for (int i = 0; i < 3; i++) {
            graphics.setColor(getColor());
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1, y1, x2, y2);
        }
        //9) 将缓存的图片输出到响应输出流中
        //参数1：要输出的缓存图片，参数2：格式，参数3：输出到哪个流中
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "jpeg", outputStream);

        //随机生成一个key，前面加上code::
        String key = RedisConst.USERS_VALIDATE_CODE + ":" + UUID.randomUUID().toString().replace("-", "");
        //得到验证码，将生成的字符串放到Redis中，键随机生成，10分钟过期
        stringRedisTemplate.opsForValue().set(key, sb.toString(), Duration.ofMinutes(10));

        log.info("生成的验证码为：{}，Redis中的key是：{}", sb, key);

        Base64.Encoder encoder = Base64.getEncoder();
        String base64Img = "data:image/jpeg;base64," + encoder.encodeToString(outputStream.toByteArray());
        //返回的数据包含验证码的key和图片
        Map<String, String> data = new HashMap<>();
        data.put("key", key);  //redis中键
        data.put("base64Img", base64Img);  //图片
        //返回key和图片的base64的编码
        return ResponseEntity.ok(data);
    }

    //写一个方法随机获取颜色
    private Color getColor() {
        Random random = new Random();
        //红，绿，蓝取值0-255，随机生成 0-255之间数
        int r = random.nextInt(256);
        int g = random.nextInt(256);
        int b = random.nextInt(256);
        return new Color(r, g, b);
    }


    @Autowired
    private SmsUtil smsUtil;
    /**
     * 手机号发短信
     */
    @GetMapping("/sendSms/{telephone}")
    @ApiOperation("手机号发短信")
    public ResponseEntity<String> sendSms(@PathVariable String telephone) {
        String code = RandomStringUtils.randomNumeric(4);
        log.info("短信验证码：{}", code);
        String smsContent = "您的验证码是：" + code + "请在10分钟内输入。";  // 这里是你自定义的短信内容
        //String result = smsUtil.sendSms(telephone, smsContent);  // 这里调用实际的短信发送方法
        String result="OK";
        Assert.error(!result.equals("OK"), BusinessCode.SMS_SEND_ERROR);
        stringRedisTemplate.opsForValue().set(RedisConst.SHORT_MESSAGE_SERVICE + ":" + telephone, code, Duration.ofMinutes(5));
        String response = "给手机号：" + maskPhoneNumber(telephone) + "成功发送验证码";
        return ResponseEntity.ok(response);
    }

    /**
     * 对电话号码进行脱敏处理
     */
    private String maskPhoneNumber(String phone) {
        // 将第4、5、6、7位替换为 *
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }

    /**
     * 发短信登录或注册
     */
    @PostMapping("/smsLogin")
    @ApiOperation("发短信登录或注册")
    public ResponseEntity<?> smsLogin(@RequestBody LoginRequest params, HttpServletRequest request) {
        //获取手机号
        String telephone = params.getPhone();
        //从Redis中获取验证码
        String codeKey = RedisConst.SHORT_MESSAGE_SERVICE + ":" + telephone;
        String smsCode = stringRedisTemplate.opsForValue().get(codeKey);
        //判断验证码是否过期 Objects.isNull(smsCode)
        Assert.error(!StringUtils.hasText(smsCode), BusinessCode.INVALID_VERIFICATION);
        //判断验证码是否正确
        String code = params.getCode();
        Assert.error(!code.equals(smsCode), BusinessCode.VERIFICATION_ERROR);
        //删除验证码
        stringRedisTemplate.delete(codeKey);
        //根据手机号查询用户信息
        Users users = usersService.findByPhone(telephone);
        //如果用户不存在，创建新用户
        if (Objects.isNull(users)) {
            //创建默认密码：123
            String encode = "123";
            users = new Users();
            users.setUsername(telephone);  //账户名：手机号
            users.setPassword(encode);    //密码
            users.setPhone(telephone);   //手机号
            users.setRegistrationDate(new Date());
            usersService.save(users);
        }
        //不为空则登录成功
        return createTokenAndUserVo(request, users);
    }

    @PostMapping("/emailLogin")
    @ApiOperation("邮箱登录")
    public ResponseEntity<?> emailLogin(@RequestBody LoginRequest loginRequest, HttpServletRequest request) {
        String email = loginRequest.getEmail();
        //从redis中获取验证码
        String codeKey = RedisConst.EMAIL_ADDRESS_PREFIX + ":" + loginRequest.getEmail();
        String redisCode = stringRedisTemplate.opsForValue().get(codeKey);
        //判断验证码是否过期
        Assert.error(Objects.isNull(redisCode), BusinessCode.INVALID_VERIFICATION);
        //判断验证码是否正确
        Assert.error(!redisCode.equals(loginRequest.getCode()), BusinessCode.VERIFICATION_ERROR);
        //删除验证码
        stringRedisTemplate.delete(codeKey);

        //根据邮箱查询用户信息
        Users users = usersService.findByEmail(email);
        //如果用户不存在，创建新用户
        if (Objects.isNull(users)) {
            //创建默认密码：123
            String encode = "123";
            users = new Users();
            users.setUsername(email);  //账户名：邮箱
            users.setPassword(encode);    //密码
            users.setEmail(email);   //邮箱
            users.setRegistrationDate(new Date());
            usersService.save(users);
        }
        // 2. 创建登录成功的 Token
        return createTokenAndUserVo(request, users);
    }

//    @PutMapping("/update")
//    @ApiOperation("更新用户信息")
//    public ResponseEntity<?> updateUserInfo(@RequestBody LoginRequest loginRequest, HttpServletRequest request) {
//        String token = request.getHeader("Authorization");
//        if (StringUtils.isEmpty(token)) {
//            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("未登录");
//        }
//        // 通过token获取用户信息
//        String userId = jwtTemplate.getToken(token);
//        Users users = usersService.findById(userId);
//        if (users == null) {
//            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("用户未找到");
//        }
//        // 更新用户信息
//        users.setUsername(loginRequest.getUsername());
//        users.setEmail(loginRequest.getEmail());
//        users.setPhone(loginRequest.getPhone());
//        usersService.updateById(users);
//
//        return ResponseEntity.ok("用户信息更新成功");
//    }

    @PutMapping("/update")
    @ApiOperation("更新用户信息")
    public ResponseEntity<?> updateUserInfo(@RequestBody LoginRequest loginRequest) {
        usersService.updateUserInfo(loginRequest);
        return ResponseEntity.ok("用户信息更新成功");
    }
}
